/* 
 * Copyright 2014-2021 UME Framework, GNU General Public License 
 */
package com.u2framework.lib.tool.gen.entity;

import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;

import javax.validation.constraints.DecimalMax;
import javax.validation.constraints.DecimalMin;
import javax.validation.constraints.Digits;
import javax.validation.constraints.Max;
import javax.validation.constraints.Min;
import javax.validation.constraints.NotNull;
import javax.validation.constraints.Size;

import org.apache.commons.lang3.RegExUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.u2framework.lib.core.util.BeanUtil;
import com.u2framework.lib.core.util.SqlUtil;
import com.u2framework.lib.core.util.StringUtil;
import com.u2framework.lib.tool.gen.base.BaseGenerator;
import com.u2framework.lib.tool.gen.base.type.TypeMapper;
import com.u2framework.lib.tool.gen.entity.bean.BaseEntityBean;
import com.u2framework.lib.tool.gen.entity.bean.BaseFieldBean;
import com.u2framework.lib.tool.gen.entity.bean.EntityDescBean;
import com.u2framework.lib.tool.gen.entity.bean.FieldDescBean;

/**
 * EntityGenerator
 *
 * @author SultansOfSwing & MaYue
 */
public class EntityGenerator {
    /**
     * logger
     */
    protected Logger logger = LoggerFactory.getLogger(EntityGenerator.class);

    /**
     * entityConfigurator
     */
    private EntityConfigurator entityConfigurator;

    /**
     * EntityGenerator
     *
     * @param entityConfigurator
     * @throws IOException
     */
    public EntityGenerator(EntityConfigurator entityConfigurator) throws IOException {
        this.entityConfigurator = entityConfigurator;
    }

    /**
     * getGenDirJava
     *
     * @return
     */
    public String getGenDirJava() {
        return this.getEntityConfigurator().getGenDir();
    }

    /**
     * genDirSqlMap
     *
     * @return
     */
    public String genDirSqlMap() {
        return this.getEntityConfigurator().getGenDir();
    }

    /**
     * genDirDDL
     *
     * @return
     */
    public String genDirDDL() {
        return this.getEntityConfigurator().getGenDir() + "/ddl/";
    }

    /**
     * prepare
     */
    protected void prepare() {
        File dir = new File(this.getEntityConfigurator().getGenDir());
        if (!dir.exists()) {
            dir.mkdirs();
        }
        dir = new File(getGenDirJava());
        if (!dir.exists()) {
            dir.mkdirs();
        }
        dir = new File(genDirDDL());
        if (!dir.exists()) {
            dir.mkdirs();
        }
        dir = new File(genDirSqlMap());
        if (!dir.exists()) {
            dir.mkdirs();
        }
    }

    /**
     * execute
     *
     * @param dtoList
     * @throws Exception
     */
    public void execute(Collection<BaseEntityBean> dtoList) throws Exception {
        execute(null, dtoList);
    }

    /**
     * execute
     *
     * @param group
     * @param tableDescBeanList
     * @throws Exception
     */
    public void execute(String group, Collection<BaseEntityBean> tableDescBeanList) throws Exception {
        String databaseType = this.getEntityConfigurator().getDatabaseType();
        group = group == null ? "" : group.trim();
        prepare();

        List<EntityDescBean> entityDescBeanList = new ArrayList<EntityDescBean>(tableDescBeanList.size());

        for (BaseEntityBean e : tableDescBeanList) {
            EntityDescBean entityDescBean = createEntityDescBean(e, databaseType);
            entityDescBeanList.add(entityDescBean);
        }

        String allddlfileName = genDirDDL() + "/" + group + "_DDL.sql";
        String vm = this.getEntityConfigurator().getTemplateSqlBat();

        if (new File(vm).exists()) {
            new BaseGenerator(vm).execute("beanList", entityDescBeanList, allddlfileName);
            logger.info("[" + allddlfileName + "] created.");
        }

        // Generate Each DDL File
        for (EntityDescBean entityDescBean : entityDescBeanList) {
            String ddlfileName = genDirDDL() + "/" + entityDescBean.getTblAlias() + ".sql";
            vm = this.getEntityConfigurator().getTemplateSql();
            if (!new File(vm).exists()) {
                continue;
            }
            new BaseGenerator(vm).execute("bean", entityDescBean, ddlfileName);
            logger.info("[" + ddlfileName + "] created.");
        }

        for (EntityDescBean entityDescBean : entityDescBeanList) {
            String sqlMapfileName = new BaseGenerator(vm).createPackageDir(genDirSqlMap(), entityDescBean.getTableMapperPackage()) + entityDescBean.getTableMapperClass() + ".xml";
            vm = this.getEntityConfigurator().getTemplateSqlMap();
            if (!new File(vm).exists()) {
                continue;
            }
            new BaseGenerator(vm).execute("bean", entityDescBean, sqlMapfileName);
            logger.info("[" + sqlMapfileName + "] created.");
        }

        // Generate Entity class
        if (new File(this.getEntityConfigurator().getTemplateEntity()).exists()) {
            BaseGenerator cg = new BaseGenerator(this.getEntityConfigurator().getTemplateEntity());
            for (EntityDescBean entityDescBean : entityDescBeanList) {
                String fileName = cg.createPackageDir(getGenDirJava(), entityDescBean.getTableEntityPackage()) + entityDescBean.getTableEntityClass() + ".java";
                cg.execute("bean", entityDescBean, fileName);
                logger.info("[" + fileName + "] created.");
            }
        }

        // Generate Mapper class
        if (new File(this.getEntityConfigurator().getTemplateEntityMapper()).exists()) {
            BaseGenerator cg = new BaseGenerator(this.getEntityConfigurator().getTemplateEntityMapper());
            for (EntityDescBean entityDescBean : entityDescBeanList) {
                String fileName = cg.createPackageDir(getGenDirJava(), entityDescBean.getTableMapperPackage()) + entityDescBean.getTableMapperClass() + ".java";
                cg.execute("bean", entityDescBean, fileName);
                logger.info("[" + fileName + "] created.");
            }
        }

        // Generate Crud Service interface
        if (new File(this.getEntityConfigurator().getTemplateCrudInterface()).exists()) {
            BaseGenerator cgCrudInterface = new BaseGenerator(this.getEntityConfigurator().getTemplateCrudInterface());
            for (EntityDescBean entityDescBean : entityDescBeanList) {
                String packageName = entityDescBean.getTableCrudServiceInterfacePackage();
                String fileName = cgCrudInterface.createPackageDir(getGenDirJava(), packageName) + entityDescBean.getTableCrudServiceInterface() + ".java";
                cgCrudInterface.execute("bean", entityDescBean, fileName);
                logger.info("[" + fileName + "] created.");
            }
        }
        // Generate Crud Service implement class
        if (new File(this.getEntityConfigurator().getTemplateCrudImpl()).exists()) {
            BaseGenerator cgCrudClass = new BaseGenerator(this.getEntityConfigurator().getTemplateCrudImpl());
            for (EntityDescBean entityDescBean : entityDescBeanList) {
                String packageName = entityDescBean.getTableCrudServicePackage();
                String fileName = cgCrudClass.createPackageDir(getGenDirJava(), packageName) + entityDescBean.getTableCrudServiceClass() + ".java";
                cgCrudClass.execute("bean", entityDescBean, fileName);
                logger.info("[" + fileName + "] created.");
            }
        }

        logger.info("DDL,SqlMap,Entity,CrudService have been generated.");
    }

    /**
     * createEntityDescBean
     *
     * @param baseEntityBean
     * @param databaseType
     * @return
     */
    public EntityDescBean createEntityDescBean(BaseEntityBean baseEntityBean, String databaseType) {
        EntityConfigurator entityConfigurator = this.getEntityConfigurator();
        EntityDescBean entityDescBean = this.copyFromBaseBean(baseEntityBean);
        entityDescBean.setClassName(entityDescBean.getTblName());
        String javaStyleName = StringUtil.firstCharToUpperCase(StringUtil.underlineToCamelStype(entityDescBean.getTblAlias()));
        entityDescBean.setClassId(javaStyleName + entityConfigurator.getGenEntityExtension());
        entityDescBean.setClassOriId(javaStyleName);
        entityDescBean.setClassOriIdInLowCase(javaStyleName.toLowerCase());
        entityDescBean.setClassOriIdInUpperCase(javaStyleName.toUpperCase());
        entityDescBean.setTableCrudServiceInterface(javaStyleName + entityConfigurator.getGenCrudInterfaceExtension());
        entityDescBean.setTableCrudServiceClass(javaStyleName + entityConfigurator.getGenCrudClassExtension());
        entityDescBean.setTableCrudApiClass(javaStyleName + entityConfigurator.getGenCrudApiExtension());
        entityDescBean.setTableMapperClass(javaStyleName + entityConfigurator.getGenEntityMapperExtension());
        entityDescBean.setTableEntityClass(javaStyleName + entityConfigurator.getGenEntityExtension());
        entityDescBean.setSqlMapXmlFile(javaStyleName + entityConfigurator.getGenSqlMapXmlExtension());

        // entityDescBean.setCurrentDate(new SimpleDateFormat("yyyy/MM/dd").format(new java.util.Date()));
        entityDescBean.setBasePackage(entityConfigurator.getBasePackage());
        if (!entityConfigurator.getGenCrudPackageExtension().equals("")) {
            entityDescBean.setTableCrudServiceInterfacePackage(entityConfigurator.getBasePackage() + "." + entityConfigurator.getGenCrudPackageExtension());
        } else {
            entityDescBean.setTableCrudServiceInterfacePackage(entityConfigurator.getBasePackage());
        }

        if (!entityConfigurator.getGenCrudApiPackageExtension().equals("")) {
            entityDescBean.setTableCrudApiPackage(entityConfigurator.getBasePackage() + "." + entityConfigurator.getGenCrudApiPackageExtension());
            entityDescBean.setTableCrudServicePackage(entityConfigurator.getBasePackage() + "." + entityConfigurator.getGenCrudPackageExtension() + ".impl");
        } else {
            entityDescBean.setTableCrudApiPackage(entityConfigurator.getBasePackage());
            entityDescBean.setTableCrudServicePackage(entityConfigurator.getBasePackage() + ".impl");
        }

        if (!entityConfigurator.getGenMapperPackageExtension().equals("")) {
            entityDescBean.setTableMapperPackage(entityConfigurator.getBasePackage() + "." + entityConfigurator.getGenMapperPackageExtension());
        } else {
            entityDescBean.setTableMapperPackage(entityConfigurator.getBasePackage());
        }
        if (!entityConfigurator.getGenEntityPackageExtension().equals("")) {
            entityDescBean.setTableEntityPackage(entityConfigurator.getBasePackage() + "." + entityConfigurator.getGenEntityPackageExtension());
        } else {
            entityDescBean.setTableEntityPackage(entityConfigurator.getBasePackage());
        }

        for (FieldDescBean field : entityDescBean.getFieldList()) {
            this.buildEntityField(field, databaseType);
            // Group PK fields
            if (field.isColPK()) {
                entityDescBean.getPrimaryKeyFieldList().add(field);
            } else {
                entityDescBean.getNonPrimaryKeyFieldList().add(field);
            }
            // Group OptimisticCheck fields
            if (field.isFlagOptimisticCheck()) {
                entityDescBean.getOptimisticCheckFieldlList().add(field);
            }
            // Group AutoIncrement fields
            if (field.isFlagAutoIncrement()) {
                entityDescBean.getAutoIncrementFieldList().add(field);
            } else if (field.isFlagLogicalDelete()) {
                entityDescBean.getLogicalDeleteFieldlList().add(field);
            } else if (field.isFlagCreatorId()) {
                entityDescBean.getCreatorIdFieldlList().add(field);
            } else if (field.isFlagUpdaterId()) {
                entityDescBean.getUpdaterIdFieldlList().add(field);
            } else if (field.isFlagCreateTime()) {
                entityDescBean.getCreateTimeFieldlList().add(field);
            } else if (field.isFlagUpdateTime()) {
                entityDescBean.getUpdateTimeFieldlList().add(field);
            } else if (field.isFlagUpdateVersion()) {
                entityDescBean.getUpdateVersionFieldlList().add(field);
            }
        }

        if (entityDescBean.getLogicalDeleteFieldlList().size() > 1) {
            throw new RuntimeException("Can not deinfine multiple logically deleted fields in one table, violation field is " + entityDescBean.getTblId() + "." + entityDescBean.getLogicalDeleteFieldlList().get(1).getColId());
        }
        if (entityDescBean.getUpdateVersionFieldlList().size() > 1) {
            throw new RuntimeException("Can not deinfine multiple update version fields in one table, violation field is " + entityDescBean.getTblId() + "." + entityDescBean.getUpdateVersionFieldlList().get(1).getColId());
        }

        buildEntityAnnotation(entityDescBean);
        buildEntityImport(entityDescBean);
        return entityDescBean;
    }

    /**
     * copyFromBaseBean
     *
     * @param baseBean
     * @return
     */
    private EntityDescBean copyFromBaseBean(BaseEntityBean baseBean) {
        EntityDescBean entity = new EntityDescBean();
        entity.setTblId(baseBean.getTblId());
        entity.setTblAlias(baseBean.getTblAlias());
        entity.setTblName(baseBean.getTblName());
        entity.setTblDivision(baseBean.getTblDivision());
        entity.setDatabaseType(baseBean.getDatabaseType());
        entity.setTblSpace(baseBean.getTblSpace());
        entity.setCreateDefaultColumns(baseBean.isCreateDefaultColumns());
        List<FieldDescBean> filedList = new ArrayList<>(baseBean.getBaseFieldList().size());
        for (BaseFieldBean baseFiled : baseBean.getBaseFieldList()) {
            FieldDescBean field = new FieldDescBean();
            BeanUtil.copyProperties(baseFiled, field);
            filedList.add(field);
        }
        entity.setFieldList(filedList);
        return entity;
    }

    /**
     * buildEntityField
     *
     * @param field
     * @param databaseCategory
     */
    protected void buildEntityField(FieldDescBean field, String databaseCategory) {
        // process for Java Naming Rules
        String colId = field.getColId();
        String fieldId = null;
        // remove 'is_' from col_id
        if (entityConfigurator.getRemoveBooleanColumnIsPrefix() && colId.toUpperCase().startsWith("IS_")) {
            colId = colId.substring(3);
            fieldId = StringUtil.underlineToCamelStype(colId);
        } else {
            fieldId = StringUtil.underlineToCamelStype(colId);
        }
        field.setFieldId(fieldId);
        field.setFieldName(field.getColName());
        TypeMapper typeMapper = this.getEntityConfigurator().getTypeMapper();
        String dbDataType = typeMapper.getDbDataType(field.getColBizType(), field, databaseCategory);
        String javaDataType = typeMapper.getJavaType(field.getColBizType(), field, databaseCategory);
        String fieldJdbcType = typeMapper.getJdbcType(field.getColBizType(), field, databaseCategory);
        field.setColDbType(dbDataType);
        field.setFieldType(javaDataType);
        field.setFieldJdbcType(fieldJdbcType);
        String fieldIdFirstCharCap = StringUtil.underlineToCamelStypeWithFirstCharUpperCase(colId);
        String fieldGetter = null;
        if ("Boolean".equals(javaDataType) && !entityConfigurator.getRemoveBooleanColumnIsPrefix()) {
            fieldGetter = "is" + fieldIdFirstCharCap;
        } else {
            fieldGetter = "get" + fieldIdFirstCharCap;
        }
        field.setFieldGetter(fieldGetter);
        field.setFieldSetter(("set") + fieldIdFirstCharCap);
        String length = field.getColLength();
        if (StringUtil.isNotEmpty(length)) {
            if (length.contains(",")) {
                String[] arr = length.split(",");
                field.setColMaxLength(Integer.parseInt(arr[0].trim()));
                field.setColLength(arr[0].trim());
                field.setColPrecision(Integer.parseInt(arr[0].trim()));
                field.setColScale(Integer.parseInt(arr[1].trim()));
                setColDbTypeDDL(field, dbDataType + "(" + arr[0].trim() + "," + arr[1].trim() + ")");
            } else if (length.contains("-")) {
                String[] arr = length.split("-");
                field.setColMinLength(Integer.parseInt(arr[0].trim()));
                field.setColMaxLength(Integer.parseInt(arr[1].trim()));
                field.setColLength(arr[1].trim());
                setColDbTypeDDL(field, dbDataType + "(" + length + ")");
            } else {
                field.setColMaxLength(Integer.parseInt(length));
                field.setColLength(length);
                setColDbTypeDDL(field, dbDataType + "(" + length + ")");
            }
        } else {
            field.setColLength("");
            setColDbTypeDDL(field, dbDataType);
        }

        if (databaseCategory.equalsIgnoreCase("MYSQL") && (field.getColDbType().equalsIgnoreCase("VARCHAR") || field.getColDbType().equalsIgnoreCase("CHAR"))) {
            field.setColDbTypeDDL(field.getColDbTypeDDL() + " BINARY");
        }
        if (field.isColPK()) {
            field.setColNotNull(field.isColPK());
        }
        if (field.isColNotNull()) {
            field.setColNotNullDDL("not null");
        } else {
            field.setColNotNullDDL("");
        }

        String colDefaultValue = field.getColDefaultValue();
        String colDefaultValueDDL = "";
        String colDefaultValueJava = "";
        if (field.isFlagAutoIncrement()) {
            if (databaseCategory.equalsIgnoreCase("MYSQL")) {
                field.setColDefaultValueDDL(" auto_increment primary key ");
            } else if (databaseCategory.equalsIgnoreCase("MYSQL")) {
                field.setColDbTypeDDL("serial primary key ");
            }
        } else if (StringUtil.isNotEmpty(colDefaultValue)) {
            colDefaultValueJava = colDefaultValue;
            if (colDefaultValueJava.startsWith("'") && colDefaultValueJava.endsWith("'") || colDefaultValueJava.startsWith("\"") && colDefaultValueJava.endsWith("\"")) {
                colDefaultValueJava = colDefaultValueJava.substring(1, colDefaultValueJava.length());
            }
            String jtype = field.getFieldType();
            if (jtype.equals("String")) {
                colDefaultValueDDL = "default " + StringUtil.addSingleQuota(colDefaultValueJava);
                colDefaultValueJava = StringUtil.addDoubleQuota(colDefaultValueJava);
            } else if (jtype.equals("java.sql.Timestamp")) {
                colDefaultValueDDL = "default " + SqlUtil.getToTimestampFuncStr(databaseCategory, colDefaultValueJava);
                colDefaultValueJava = "java.sql.Timestamp.valueOf" + StringUtil.addParentheses(StringUtil.addDoubleQuota(colDefaultValueJava));
            } else if (jtype.equals("java.sql.Date")) {
                colDefaultValueDDL = "default " + SqlUtil.getToDateFuncStr(databaseCategory, colDefaultValueJava);
                colDefaultValueJava = "java.sql.Date.valueOf" + StringUtil.addParentheses(StringUtil.addDoubleQuota(colDefaultValueJava));;
            } else if (jtype.equals("java.sql.Time")) {
                colDefaultValueDDL = "default " + SqlUtil.getToTimeFuncStr(databaseCategory, colDefaultValueJava);
                colDefaultValueJava = "java.sql.Time.valueOf" + StringUtil.addParentheses(StringUtil.addDoubleQuota(colDefaultValueJava));
            } else if (jtype.equals("java.util.Date")) {
                colDefaultValueDDL = "default " + SqlUtil.getToTimestampFuncStr(databaseCategory, colDefaultValueJava);
                colDefaultValueJava = "java.sql.Timestamp.valueOf" + StringUtil.addParentheses(StringUtil.addDoubleQuota(colDefaultValueJava));
            } else if (jtype.equals("java.math.BigInteger") || jtype.equals("Integer") || jtype.equals("Short") || jtype.equals("Long")) {
                if (colDefaultValueJava.contains(".")) {
                    colDefaultValueJava = colDefaultValueJava.split("\\.")[0];
                }
                colDefaultValueDDL = "default " + colDefaultValueJava;
            } else if (jtype.equals("java.math.BigDecimal")) {
                colDefaultValueDDL = "default " + colDefaultValueJava;
                colDefaultValueJava = "new java.math.BigDecimal" + StringUtil.addParentheses(StringUtil.addDoubleQuota(colDefaultValueJava));
            } else if (jtype.equals("Boolean")) {
                String val = colDefaultValueJava.equalsIgnoreCase("true") || colDefaultValueJava.equals("1") ? "1" : "0";
                colDefaultValueDDL = "DEFAULT " + StringUtil.addSingleQuota(val);
                colDefaultValueJava = val.equals("1") ? "true" : "false";
            } else {
                colDefaultValueDDL = "default " + colDefaultValueJava;
            }
        } else if (databaseCategory.equalsIgnoreCase("MYSQL") && StringUtil.isEmpty(colDefaultValue) && field.getColDbType().toUpperCase().startsWith("TIMESTAMP")) {
            if (field.isColNotNull()) {
                colDefaultValueDDL = "default current_timestamp()";
            } else {
                colDefaultValueDDL = "null default null";
            }
        }
        field.setColDefaultValueDDL(colDefaultValueDDL);
        field.setColDefaultValueJava(colDefaultValueJava);
        this.buildEntityFieldAnnotation(field, databaseCategory);
    }

    /**
     * buildEntityFieldAnnotation
     *
     * @param field
     * @param databaseCategory
     */
    protected void buildEntityFieldAnnotation(FieldDescBean field, String databaseCategory) {
        List<String> fieldAnnotationList = field.getFieldAnnotationList();
        String id = field.getFieldId();
        String type = field.getFieldType();
        String name = field.getColName();
        String len = field.getColLength();
        Integer minLen = field.getColMinLength();
        Integer maxLen = field.getColMaxLength();
        String minVal = field.getColMinValue();
        String maxVal = field.getColMaxValue();
        Integer precision = field.getColPrecision();
        Integer scale = field.getColScale();
        String defaultVal = field.getColDefaultValue();
        String format = field.getColFormat();

        StringBuilder swaggerAnno = new StringBuilder();
        swaggerAnno.append(entityConfigurator.isUseSwagger2Annotation() ? "@ApiModelProperty": "@Schema");
        swaggerAnno.append("(name = \"");
        swaggerAnno.append(id);
        swaggerAnno.append("\", ");
        swaggerAnno.append(entityConfigurator.isUseSwagger2Annotation() ? "value = \"": "title = \"");
        // 进行特殊字符转换，避免引起生成后代码出现错误
        name = RegExUtils.replacePattern(name, "\"", "\\\\\"");
        name = RegExUtils.replacePattern(name, "\n", " ");
        swaggerAnno.append(name);
        swaggerAnno.append("\"");
        swaggerAnno.append(field.isColNotNull() ? ", required = true)" : ")");
        fieldAnnotationList.add(swaggerAnno.toString());

        if (field.isColNotNull()) {
            String anno = "@" + NotNull.class.getName() + "(message = \"" + name + "不能为空\")";
            fieldAnnotationList.add(anno);
        }
        if ("String".equals(type)) {
            if (minLen != null && maxLen != null) {
                String anno = "@" + Size.class.getName() + "(min = " + minLen + ", max = " + maxLen + ", message = \"" + name + "长度不能少于" + minLen + "也不能超过" + maxLen + "\")";
                fieldAnnotationList.add(anno);
            } else if (maxLen != null) {
                String anno = "@" + Size.class.getName() + "(max = " + maxLen + ", message = \"" + name + "长度不能超过" + maxLen + "\")";
                fieldAnnotationList.add(anno);
            }
            if (StringUtil.isNotEmpty(minVal)) {
                String anno = "@" + Min.class.getName() + "(value = " + minVal + ", message = \"" + name + "最小值为" + minVal + "\")";
                fieldAnnotationList.add(anno);
            }
            if (StringUtil.isNotEmpty(maxVal)) {
                String anno = "@" + Max.class.getName() + "(value = " + maxVal + ", message = \"" + name + "最大值为" + maxVal + "\")";
                fieldAnnotationList.add(anno);
            }
        } else if ("Integer".equals(type) || "Short".equals(type) || "Long".equals(type) || "java.math.BigInteger".equals(type)) {
            if (maxLen != null) {
                String anno = "@" + Digits.class.getName() + "(integer = " + maxLen + ", fraction = 0, message = \"" + name + "长度不能超过" + maxLen + "\")";
                fieldAnnotationList.add(anno);
            }
            if (StringUtil.isNotEmpty(minVal)) {
                String anno = "@" + Min.class.getName() + "(value = " + minVal + ", message = \"" + name + "最小值为" + minVal + "\")";
                fieldAnnotationList.add(anno);
            }
            if (StringUtil.isNotEmpty(maxVal)) {
                String anno = "@" + Max.class.getName() + "(value = " + maxVal + ", message = \"" + name + "最大值为" + maxVal + "\")";
                fieldAnnotationList.add(anno);
            }
        } else if ("Float".equals(type) || "Double".equals(type) || "java.math.BigDecimal".equals(type)) {
            if (precision != null && scale != null) {
                String anno = "@" + Digits.class.getName() + "(integer = " + precision + ", fraction = " + scale + ", message = \"" + name + "最大位数为" + precision + ",最大精度为" + scale + "\")";
                fieldAnnotationList.add(anno);
            } else if (StringUtil.isNotEmpty(len) && scale != null) {
                String anno = "@" + Digits.class.getName() + "(integer = " + len + ", fraction = " + scale + ", message = \"" + name + "最大位数为" + len + ",最大精度为" + scale + "\")";
                fieldAnnotationList.add(anno);
            } else if (StringUtil.isNotEmpty(len)) {
                String anno = "@" + Digits.class.getName() + "(integer = " + len + ", fraction = 0, message = \"" + name + "最大位数为" + len + ",最大精度为" + scale + "\")";
                fieldAnnotationList.add(anno);
            }
            if (StringUtil.isNotEmpty(minVal)) {
                String anno = "@" + DecimalMin.class.getName() + "(value = \"" + minVal + "\", message = \"" + name + "最小值为" + minVal + "\")";
                fieldAnnotationList.add(anno);
            }
            if (StringUtil.isNotEmpty(maxVal)) {
                String anno = "@" + DecimalMax.class.getName() + "(value = \"" + maxVal + "\", message = \"" + name + "最大值为" + maxVal + "\")";
                fieldAnnotationList.add(anno);
            }
        }

        if (field.isFlagAutoIncrement()) {
            // Skip
        } else if (field.isFlagCreatorId()) {
            String anno = "@" + com.u2framework.lib.core.domain.annotation.CreatorId.class.getName();
            fieldAnnotationList.add(anno);
        } else if (field.isFlagUpdaterId()) {
            String anno = "@" + com.u2framework.lib.core.domain.annotation.UpdaterId.class.getName();
            fieldAnnotationList.add(anno);
        } else if (field.isFlagCreateTime()) {
            String anno = "@" + com.u2framework.lib.core.domain.annotation.CreateTime.class.getName();
            fieldAnnotationList.add(anno);
        } else if (field.isFlagUpdateTime()) {
            String anno = "@" + com.u2framework.lib.core.domain.annotation.UpdateTime.class.getName();
            fieldAnnotationList.add(anno);
        } else if (field.isFlagUpdateVersion()) {
            Integer start = StringUtil.isNotEmpty(defaultVal) ? Integer.parseInt(defaultVal) : 1;
            String anno = "@" + com.u2framework.lib.core.domain.annotation.UpdateVersion.class.getName();
            anno = anno + "(start = " + start + ")";
            fieldAnnotationList.add(anno);
        } else if (field.isFlagLogicalDelete()) {
            String anno = "@" + com.u2framework.lib.core.domain.annotation.LogicalDelete.class.getName();
            if (StringUtil.isNotEmpty(format)) {
                format = format.replace(',', ':');
                String[] arr = format.split(":");
                String off = arr[0].trim();
                String on = arr.length > 1 ? arr[1].trim() : field.getFlagLogicalDeleteValueOn();
                off = StringUtil.trimDoubleQuota(off);
                on = StringUtil.trimDoubleQuota(on);                
                anno += "(on = \"" + on + "\", off = \"" + off + "\")";
                if (type.equals("String")) {
                    off = StringUtil.addSingleQuota(off);
                    on = StringUtil.addSingleQuota(on);
                }
                field.setFlagLogicalDeleteValueOn(off);
                field.setFlagLogicalDeleteValueOn(on);
            }
            fieldAnnotationList.add(anno);
        }

    }

    /**
     * buildEntityAnnotation
     * 
     * @param bean
     */
    protected void buildEntityAnnotation(EntityDescBean bean) {
        String anno = entityConfigurator.isUseSwagger2Annotation() ? "@ApiModel(value = \"" + bean.getTableEntityClass() + "\", description=\"" + bean.getClassName() + "\")" : "@Schema(name = \"" + bean.getTableEntityClass() + "\", title = \"" + bean.getClassName() + "\")";
        bean.getClassAnnotationList().add(anno);
    }

    /**
     * buildEntityImport
     *
     * @param bean
     */
    protected void buildEntityImport(EntityDescBean bean) {
        bean.getClassImportList().add(entityConfigurator.isUseSwagger2Annotation() ? "io.swagger.annotations.*" : "io.swagger.v3.oas.annotations.media.Schema");
    }

    /**
     * isTextType
     *
     * @param colType
     * @return
     */
    protected boolean isTextType(String bizType, String colType) {
        colType = colType.trim().toUpperCase();
        if ("文本".equals(bizType) || colType.startsWith("CHAR") || colType.startsWith("VARCHAR") || colType.startsWith("TEXT")) {
            return true;
        }
        return false;
    }

    /**
     * setColDbTypeDDL
     *
     * @param field
     * @param value
     */
    private void setColDbTypeDDL(FieldDescBean field, String value) {
        if (StringUtil.isEmpty(field.getColDbTypeDDL())) {
            field.setColDbTypeDDL(value);
        }
    }

    /**
     * @return the entityConfigurator
     */
    public EntityConfigurator getEntityConfigurator() {
        return entityConfigurator;
    }

    /**
     * @param entityConfigurator the entityConfigurator to set
     */
    public void setEntityConfigurator(EntityConfigurator entityConfigurator) {
        this.entityConfigurator = entityConfigurator;
    }

}
